"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
var _vue = require("vue");
var _xeUtils = _interopRequireDefault(require("xe-utils"));
var _ui = require("../../ui");
var _dom = require("../../ui/src/dom");
var _utils = require("../../ui/src/utils");
var _vn = require("../../ui/src/vn");
var _loading = _interopRequireDefault(require("../../loading/src/loading"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _default = exports.default = (0, _vue.defineComponent)({
  name: 'VxeMenu',
  props: {
    modelValue: [String, Number],
    expandAll: Boolean,
    collapsed: {
      type: Boolean,
      default: null
    },
    collapseFixed: Boolean,
    loading: Boolean,
    options: {
      type: Array,
      default: () => []
    },
    size: {
      type: String,
      default: () => (0, _ui.getConfig)().image.size || (0, _ui.getConfig)().size
    }
  },
  emits: ['update:modelValue', 'click'],
  setup(props, context) {
    const {
      emit,
      slots
    } = context;
    const xID = _xeUtils.default.uniqueId();
    const $xeLayoutAside = (0, _vue.inject)('$xeLayoutAside', null);
    const refElem = (0, _vue.ref)();
    const refCollapseElem = (0, _vue.ref)();
    const {
      computeSize
    } = (0, _ui.useSize)(props);
    const reactData = (0, _vue.reactive)({
      initialized: !!props.collapsed,
      isEnterCollapse: false,
      collapseStyle: {},
      collapseZindex: 0,
      activeName: props.modelValue,
      menuList: [],
      itemHeight: 1
    });
    const refMaps = {
      refElem
    };
    const computeIsCollapsed = (0, _vue.computed)(() => {
      const {
        collapsed
      } = props;
      if (_xeUtils.default.isBoolean(collapsed)) {
        return collapsed;
      }
      if ($xeLayoutAside) {
        return !!$xeLayoutAside.props.collapsed;
      }
      return false;
    });
    const computeCollapseWidth = (0, _vue.computed)(() => {
      let collapseWidth = '';
      if ($xeLayoutAside) {
        collapseWidth = $xeLayoutAside.props.collapseWidth || '';
      }
      return collapseWidth;
    });
    const computeCollapseEnterWidth = (0, _vue.computed)(() => {
      let width = '';
      if ($xeLayoutAside) {
        width = $xeLayoutAside.props.width || '';
      }
      return width;
    });
    const computeMaps = {
      computeSize
    };
    const $xeMenu = {
      xID,
      props,
      context,
      reactData,
      getRefMaps: () => refMaps,
      getComputeMaps: () => computeMaps
    };
    const getMenuTitle = item => {
      return `${item.title || item.name}`;
    };
    const updateZindex = () => {
      if (reactData.collapseZindex < (0, _utils.getLastZIndex)()) {
        reactData.collapseZindex = (0, _utils.nextZIndex)();
      }
    };
    const updateActiveMenu = isDefExpand => {
      const {
        activeName
      } = reactData;
      _xeUtils.default.eachTree(reactData.menuList, (item, index, items, path, parent, nodes) => {
        if (item.itemKey === activeName) {
          nodes.forEach(obj => {
            obj.isActive = true;
            if (isDefExpand) {
              obj.isExpand = true;
            }
          });
          item.isExactActive = true;
        } else {
          item.isExactActive = false;
          item.isActive = false;
        }
      }, {
        children: 'childList'
      });
    };
    const updateMenuConfig = () => {
      const {
        options,
        expandAll
      } = props;
      reactData.menuList = _xeUtils.default.mapTree(options, (item, index, items, path, parent) => {
        const objItem = Object.assign(Object.assign({}, item), {
          parentKey: parent ? parent.name || path.slice(0, path.length - 1).join(',') : '',
          level: path.length,
          itemKey: item.name || path.join(','),
          isExactActive: false,
          isActive: false,
          isExpand: _xeUtils.default.isBoolean(item.expanded) ? item.expanded : !!expandAll,
          hasChild: item.children && item.children.length > 0
        });
        return objItem;
      }, {
        children: 'children',
        mapChildren: 'childList'
      });
    };
    const updateCollapseStyle = () => {
      const {
        collapseFixed
      } = props;
      if (collapseFixed) {
        (0, _vue.nextTick)(() => {
          const {
            isEnterCollapse
          } = reactData;
          const isCollapsed = computeIsCollapsed.value;
          const collapseEnterWidth = computeCollapseEnterWidth.value;
          const collapseWidth = computeCollapseWidth.value;
          const el = refElem.value;
          if (el) {
            const clientRect = el.getBoundingClientRect();
            const parentNode = el.parentNode;
            reactData.collapseStyle = isCollapsed ? {
              top: (0, _dom.toCssUnit)(clientRect.top),
              left: (0, _dom.toCssUnit)(clientRect.left),
              height: (0, _dom.toCssUnit)(parentNode.clientHeight),
              width: isEnterCollapse ? collapseEnterWidth ? (0, _dom.toCssUnit)(collapseEnterWidth) : '' : collapseWidth ? (0, _dom.toCssUnit)(collapseWidth) : '',
              zIndex: reactData.collapseZindex
            } : {};
          }
        });
      }
    };
    const handleCollapseMenu = () => {
      const {
        collapseFixed
      } = props;
      if (collapseFixed) {
        const {
          initialized
        } = reactData;
        const isCollapsed = computeIsCollapsed.value;
        if (isCollapsed) {
          if (!initialized) {
            reactData.initialized = true;
            (0, _vue.nextTick)(() => {
              const collapseEl = refCollapseElem.value;
              if (collapseEl) {
                document.body.appendChild(collapseEl);
              }
            });
          }
        }
        reactData.isEnterCollapse = false;
        updateZindex();
        updateCollapseStyle();
      }
    };
    const handleClickIconCollapse = (evnt, item) => {
      const {
        hasChild,
        isExpand
      } = item;
      if (hasChild) {
        evnt.stopPropagation();
        evnt.preventDefault();
        item.isExpand = !isExpand;
      }
    };
    const emitModel = value => {
      reactData.activeName = value;
      emit('update:modelValue', value);
    };
    const handleClickMenu = (evnt, item) => {
      const {
        itemKey,
        routerLink,
        hasChild
      } = item;
      if (routerLink) {
        emitModel(itemKey);
        handleMenuMouseleave();
      } else {
        if (hasChild) {
          handleClickIconCollapse(evnt, item);
        } else {
          emitModel(itemKey);
          handleMenuMouseleave();
        }
      }
      dispatchEvent('click', {
        menu: item
      }, evnt);
    };
    const handleMenuMouseenter = () => {
      const {
        collapseStyle
      } = reactData;
      const collapseEnterWidth = computeCollapseEnterWidth.value;
      reactData.collapseStyle = Object.assign({}, collapseStyle, {
        width: collapseEnterWidth ? (0, _dom.toCssUnit)(collapseEnterWidth) : ''
      });
      reactData.isEnterCollapse = true;
    };
    const handleMenuMouseleave = () => {
      const {
        collapseStyle
      } = reactData;
      const el = refElem.value;
      reactData.collapseStyle = Object.assign({}, collapseStyle, {
        width: el ? (0, _dom.toCssUnit)(el.offsetWidth) : ''
      });
      reactData.isEnterCollapse = false;
    };
    const callSlot = (slotFunc, params) => {
      if (slotFunc) {
        if (_xeUtils.default.isString(slotFunc)) {
          slotFunc = slots[slotFunc] || null;
        }
        if (_xeUtils.default.isFunction(slotFunc)) {
          return (0, _vn.getSlotVNs)(slotFunc(params));
        }
      }
      return [];
    };
    const dispatchEvent = (type, params, evnt) => {
      emit(type, (0, _ui.createEvent)(evnt, {
        $menu: $xeMenu
      }, params));
    };
    const menuMethods = {
      dispatchEvent
    };
    const menuPrivateMethods = {};
    Object.assign($xeMenu, menuMethods, menuPrivateMethods);
    const renderMenuTitle = item => {
      const {
        icon,
        isExpand,
        hasChild,
        slots: itemSlots
      } = item;
      const optionSlot = itemSlots ? itemSlots.default : slots.option;
      const title = getMenuTitle(item);
      const isCollapsed = computeIsCollapsed.value;
      return [(0, _vue.h)('div', {
        class: 'vxe-menu--item-link-icon'
      }, icon ? [(0, _vue.h)('i', {
        class: icon
      })] : []), optionSlot ? (0, _vue.h)('div', {
        class: 'vxe-menu--item-custom-title'
      }, callSlot(optionSlot, {
        option: item,
        collapsed: isCollapsed
      })) : (0, _vue.h)('div', {
        class: 'vxe-menu--item-link-title',
        title
      }, title), hasChild ? (0, _vue.h)('div', {
        class: 'vxe-menu--item-link-collapse',
        onClick(evnt) {
          handleClickIconCollapse(evnt, item);
        }
      }, [(0, _vue.h)('i', {
        class: isExpand ? (0, _ui.getIcon)().MENU_ITEM_EXPAND_OPEN : (0, _ui.getIcon)().MENU_ITEM_EXPAND_CLOSE
      })]) : (0, _vue.createCommentVNode)()];
    };
    const renderDefaultChildren = item => {
      const {
        itemKey,
        level,
        hasChild,
        isActive,
        isExactActive,
        isExpand,
        routerLink,
        childList
      } = item;
      const {
        isEnterCollapse
      } = reactData;
      const isCollapsed = computeIsCollapsed.value;
      if (item.permissionCode) {
        if (!_ui.permission.checkVisible(item.permissionCode)) {
          return (0, _vue.createCommentVNode)();
        }
      }
      return (0, _vue.h)('div', {
        key: itemKey,
        class: ['vxe-menu--item-wrapper', `vxe-menu--item-level${level}`, {
          'is--exact-active': isExactActive,
          'is--active': isActive,
          'is--expand': (!isCollapsed || isEnterCollapse) && isExpand
        }]
      }, [routerLink ? (0, _vue.h)((0, _vue.resolveComponent)('router-link'), {
        class: 'vxe-menu--item-link',
        to: routerLink,
        onClick(evnt) {
          handleClickMenu(evnt, item);
        }
      }, {
        default: () => renderMenuTitle(item)
      }) : (0, _vue.h)('div', {
        class: 'vxe-menu--item-link',
        onClick(evnt) {
          handleClickMenu(evnt, item);
        }
      }, renderMenuTitle(item)), hasChild ? (0, _vue.h)('div', {
        class: 'vxe-menu--item-group'
      }, childList.map(child => renderDefaultChildren(child))) : (0, _vue.createCommentVNode)()]);
    };
    const renderCollapseChildren = item => {
      const {
        itemKey,
        level,
        hasChild,
        isActive,
        isExactActive,
        routerLink,
        childList
      } = item;
      if (item.permissionCode) {
        if (!_ui.permission.checkVisible(item.permissionCode)) {
          return (0, _vue.createCommentVNode)();
        }
      }
      return (0, _vue.h)('div', {
        key: itemKey,
        class: ['vxe-menu--item-wrapper', `vxe-menu--item-level${level}`, {
          'is--exact-active': isExactActive,
          'is--active': isActive
        }]
      }, [routerLink ? (0, _vue.h)((0, _vue.resolveComponent)('router-link'), {
        class: 'vxe-menu--item-link',
        to: routerLink,
        onClick(evnt) {
          handleClickMenu(evnt, item);
        }
      }, {
        default: () => renderMenuTitle(item)
      }) : (0, _vue.h)('div', {
        class: 'vxe-menu--item-link',
        onClick(evnt) {
          handleClickMenu(evnt, item);
        }
      }, renderMenuTitle(item)), hasChild ? (0, _vue.h)('div', {
        class: 'vxe-menu--item-group'
      }, childList.map(child => renderDefaultChildren(child))) : (0, _vue.createCommentVNode)()]);
    };
    const renderVN = () => {
      const {
        loading
      } = props;
      const {
        initialized,
        menuList,
        collapseStyle,
        isEnterCollapse
      } = reactData;
      const vSize = computeSize.value;
      const isCollapsed = computeIsCollapsed.value;
      return (0, _vue.h)('div', {
        ref: refElem,
        class: ['vxe-menu', {
          [`size--${vSize}`]: vSize,
          'is--collapsed': isCollapsed,
          'is--loading': loading
        }]
      }, [(0, _vue.h)('div', {
        class: 'vxe-menu--item-list'
      }, menuList.map(child => isCollapsed ? renderCollapseChildren(child) : renderDefaultChildren(child))), initialized ? (0, _vue.h)('div', {
        ref: refCollapseElem,
        class: ['vxe-menu--collapse-wrapper', {
          [`size--${vSize}`]: vSize,
          'is--collapsed': isCollapsed,
          'is--enter': isEnterCollapse,
          'is--loading': loading
        }],
        style: collapseStyle,
        onMouseenter: handleMenuMouseenter,
        onMouseleave: handleMenuMouseleave
      }, [isCollapsed ? (0, _vue.h)('div', {
        class: 'vxe-menu--item-list'
      }, menuList.map(child => renderDefaultChildren(child))) : (0, _vue.createCommentVNode)()]) : (0, _vue.createCommentVNode)(),
      /**
       * 加载中
       */
      (0, _vue.h)(_loading.default, {
        class: 'vxe-list-view--loading',
        modelValue: loading
      })]);
    };
    const optFlag = (0, _vue.ref)(0);
    (0, _vue.watch)(() => props.options ? props.options.length : -1, () => {
      optFlag.value++;
    });
    (0, _vue.watch)(() => props.options, () => {
      optFlag.value++;
    });
    (0, _vue.watch)(optFlag, () => {
      updateMenuConfig();
      updateActiveMenu(true);
    });
    (0, _vue.watch)(() => props.modelValue, val => {
      reactData.activeName = val;
    });
    (0, _vue.watch)(() => reactData.activeName, () => {
      updateActiveMenu(true);
    });
    (0, _vue.watch)(computeIsCollapsed, () => {
      handleCollapseMenu();
    });
    (0, _vue.onMounted)(() => {
      _ui.globalEvents.on($xeMenu, 'resize', updateCollapseStyle);
      updateCollapseStyle();
    });
    (0, _vue.onBeforeUnmount)(() => {
      _ui.globalEvents.off($xeMenu, 'resize');
      const collapseEl = refCollapseElem.value;
      if (collapseEl) {
        const parentNode = collapseEl.parentNode;
        if (parentNode) {
          parentNode.removeChild(collapseEl);
        }
      }
    });
    updateMenuConfig();
    updateActiveMenu(true);
    $xeMenu.renderVN = renderVN;
    return $xeMenu;
  },
  render() {
    return this.renderVN();
  }
});